#ifndef __FIBER_H_
#define __FIBER_H_

#include <ucontext.h>
#include <memory>
#include <functional>
/************************************************
 * <ucontext.h> 
 * 
 * makecontext:      指明该context的入口函数
 * swapcontext:      保存当前上下文并切换到新的上下文运行
 * getcontext :      保存当前上下文
 * setcontext:       切换到新上下文
 * 
*************************************************/
/************************************************
 * Fiber 程序运行的最小单位，运行在线程上
 * 
 * thread_local var:
 * t_fiber:         线程上正在执行的fiber
 * t_threadFiber:   线程暂存协程，每个协程切出后，都会回到该协程，可以理解成一个临时变量，记录当前执行到了什么位置
 *                  t_fiber->swapIn()  将当前上下文保存在t_threadFiber中，并跳转到t_fiber中执行  
 *                  t_fiber->swapout() 跳转回到之前的t_threadFiber位置
 * 
 * 
 * State:           程序状态
 * m_ctx:           上下文
 * m_cb :           要执行的函数
 * m_stack:         协程栈,在堆上创建，默认1M，注意析构需要释放
 * m_stacksize:     栈大小，栈向下生长(高地址->低地址)
 * 
 * reset():         重置fiber的执行函数,有时候可以避免创建销毁开销
 * swapIn():        切换到当前fiber执行
 * swapOut():       退出当前fiber,切换到主协程
 * 
 * 
 * SetThis():       记录当前线程正在执行的协程，保存至变量t_fiber
 * GetThis():       返回当前线程正在执行的协程
 * YieldToHold():   切出，并将状态置为HOLD
 * YieldToReady():  切出，并将状态置为READY
 * 
 * MainFunc():      Fiber m_ctx 入口函数,执行结束后状态置为TERM，异常置为EXCEPT
 * 
 * refenrece:
 * 协程那些事儿 http://www.ilovecpp.com/2018/12/19/coroutine/
*************************************************/
namespace learnco {

class Fiber : public std::enable_shared_from_this<Fiber> {
public:
    typedef std::shared_ptr<Fiber> ptr;
    typedef ucontext_t context;
    enum State {
        INIT,   
        HOLD,   
        EXEC,   //正在执行
        TERM,   //结束
        READY, 
        EXCEPT
    };
    Fiber(std::function<void()> cb, size_t stacksize = 1024*1024);
    ~Fiber();
private:
    Fiber();    //不允许使用默认构造
private: 
    ucontext_t m_ctx;
    void* m_stack = nullptr;
    std::function<void()> m_cb;
    uint64_t m_id = 0;
    uint32_t m_stacksize = 0;
    State m_state = INIT;
    ucontext_t* m_recvctx = nullptr;


public:
    void reset(std::function<void()> cb);
    void swapIn();
    void swapIn(ucontext_t &ctx);
    void swapOut();
    void swapOut(ucontext_t* ctx);
    State getState() const { return m_state;}

public:
    static void SetThis(Fiber* f);
    static Fiber::ptr GetThis();
    static void YieldToHold();
    static void YieldToReady();
    static uint64_t TotalFibers();
    static void MainFunc();

    friend uint64_t GetFiberID();
};

//全局函数，获取fiberid
uint64_t GetFiberID();

}


#endif